const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const util = require('util');
const os = require('os');
const execPromise = util.promisify(exec);

/**
 * 自动分析MP3文件并调整BPM至130
 * 这个脚本使用ffmpeg来分析和调整MP3文件的BPM
 */

// 目标BPM值
const TARGET_BPM = 130;

/**
 * 分析音频文件的BPM
 * @param {string} filePath - MP3文件路径
 * @returns {Promise<number>} - 返回测量的BPM值
 */
async function analyzeBPM(filePath) {
  try {
    // 使用ffmpeg读取文件元数据
    const { stdout } = await execPromise(
      `ffmpeg -i "${filePath}" 2>&1`
    );
    
    // 从元数据中提取BPM信息
    const bpmMatch = stdout.match(/TBPM\s*:\s*(\d+(?:\.\d+)?)/);
    if (!bpmMatch) {
      console.warn(`无法从元数据中读取 ${path.basename(filePath)} 的BPM，将使用默认值进行处理`);
      return 0; // 返回0表示未检测到
    }
    
    const bpm = parseFloat(bpmMatch[1]);
    console.log(`从元数据中读取到 ${path.basename(filePath)} 的BPM: ${bpm}`);
    return bpm;
  } catch (error) {
    console.error(`分析文件 ${path.basename(filePath)} 的BPM时出错:`, error);
    return 0; // 出错时返回0
  }
}

/**
 * 调整音频文件的BPM
 * @param {string} filePath - 文件路径
 * @param {number} originalBPM - 原始BPM
 * @returns {Promise<void>}
 */
async function adjustBPM(filePath, originalBPM) {
  try {
    const tempPath = `${filePath}.temp.mp3`;
    
    if (originalBPM <= 0) {
      // 如果未检测到BPM，直接设置为目标BPM
      await execPromise(
        `ffmpeg -i "${filePath}" -af "atempo=${TARGET_BPM/130}" -c:a libmp3lame -q:a 0 -map_metadata 0 "${tempPath}"`
      );
    } else {
      // 计算需要调整的速度比例
      const tempo = TARGET_BPM / originalBPM;
      await execPromise(
        `ffmpeg -i "${filePath}" -af "atempo=${tempo}" -c:a libmp3lame -q:a 0 -map_metadata 0 "${tempPath}"`
      );
    }
    
    // 替换原文件
    fs.unlinkSync(filePath);
    fs.renameSync(tempPath, filePath);
    
    console.log(`已成功调整文件 ${path.basename(filePath)} 的BPM从 ${originalBPM} 到 ${TARGET_BPM}`);
  } catch (error) {
    console.error(`调整文件 ${path.basename(filePath)} 的BPM时出错:`, error);
    // 清理临时文件
    if (fs.existsSync(tempPath)) {
      fs.unlinkSync(tempPath);
    }
  }
}

/**
 * 处理单个MP3文件
 * @param {string} filePath - MP3文件路径
 * @returns {Promise<void>}
 */
async function processFile(filePath) {
  try {
    console.log(`正在分析文件: ${path.basename(filePath)}`);
    const originalBPM = await analyzeBPM(filePath);
    await adjustBPM(filePath, originalBPM);
  } catch (error) {
    console.error(`处理文件 ${path.basename(filePath)} 失败:`, error);
  }
}

/**
 * 处理目录中的所有MP3文件
 * @param {string} inputDir - 输入目录
 * @returns {Promise<void>}
 */
async function processDirectory(inputDir) {
  try {
    const files = fs.readdirSync(inputDir);
    const mp3Files = files.filter(file => path.extname(file).toLowerCase() === '.mp3');
    
    console.log(`在目录 ${inputDir} 中找到 ${mp3Files.length} 个MP3文件`);
    
    // 获取CPU核心数
    const cpuCount = os.cpus().length;
    console.log(`使用 ${cpuCount} 个CPU核心进行并行处理`);
    
    // 将文件分成多个批次
    const batchSize = Math.ceil(mp3Files.length / cpuCount);
    const batches = [];
    
    for (let i = 0; i < mp3Files.length; i += batchSize) {
      batches.push(mp3Files.slice(i, i + batchSize));
    }
    
    // 并行处理每个批次
    await Promise.all(batches.map(async (batch) => {
      for (const file of batch) {
        await processFile(path.join(inputDir, file));
      }
    }));
    
    console.log('所有文件处理完成!');
  } catch (error) {
    console.error('处理目录时出错:', error);
  }
}

// 命令行参数处理
if (require.main === module) {
  const args = process.argv.slice(2);
  
  if (args.length < 1) {
    console.log(`
使用方法:
  node autobpm.js <目录路径>
    `);
    process.exit(1);
  }
  
  const inputDir = args[0];
  processDirectory(inputDir);
}

// 导出函数以便其他模块使用
module.exports = {
  analyzeBPM,
  adjustBPM,
  processFile,
  processDirectory
};
